/*! \file image.cpp	
	This contains the implementation of the Image class.
*/

#include "image.h"

ImageHandler* ImageHandler::imageHandler = 0;

ostream& operator<<( ostream& o, Color& c ) {
	o << "r: " << c.r << " g: " << c.g << " b: " << c.b << " a: " << c.a;
	return o;
}

Color::Color( float r, float g, float b, float a ) :
	r(r),
	g(g),
	b(b),
	a(a)
{
		//~ cout << sizeof( array ) << endl;
}

Image::Image( int x, int y, int w, int h ) : 
	x(x), 
	y(y), 
	w(w), 
	h(h) 
	{
	}

TextureHandler::TextureHandler( int w, int h ) : 
	w(w),
	h(h)
	{
	}

ImageHandler::ImageHandler() {
	boundTexture = -1;
	w = -1;
	h = -1;
	workingTextureID = -1;
}

ImageHandler* ImageHandler::getInstance() {
	if ( imageHandler == 0 ) {
		imageHandler = new ImageHandler();
	}
	return imageHandler;
}

int ImageHandler::loadImage(char* fname, char* rectFile, GLuint filter ) {
	corona::Image *image = corona::OpenImage(fname, corona::PF_R8G8B8A8);
	
	if (!image) {
		// image not made
		fprintf(stderr, "Can not load %s", fname);
		exit(1);
	}
   
	TextureHandler* t = new TextureHandler( image->getWidth(), image->getHeight() );
   
	GLuint texID;
	glGenTextures(1, &texID);
	glBindTexture(GL_TEXTURE_2D, texID);
   
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
   
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   
	glTexImage2D(GL_TEXTURE_2D, 0, 4, t->w, t->h,
		0, GL_RGBA, GL_UNSIGNED_BYTE, image->getPixels());
   
	delete image; // delete corona image to free memory
   
	printf("\nCreated texture from: %s\n\tWidth:%d\n\tHeight:%d\n", fname, t->w, t->h);
	
	textures.insert( make_pair( texID, t ) );
	
	// Now, go through our rectFile and store where all of the rectangles are
	string newName;
	if ( !strcmp( rectFile, "SAME" ) ) {
		newName = fname;
		int dotPosition = newName.find_last_of( ".", newName.length() - 1 );
		cout << "DotPosition : " << dotPosition << endl;
		newName.erase( dotPosition + 1 );
		newName += "rec";
		cout << "No rectFile was specified, so defaulting to loading: " << rectFile << endl;
	} else {
		newName = fname;
	}
	cout << "NewNAme: " << newName << endl;
	
	ifstream fout;
	fout.open( newName.c_str() );
	if ( fout.fail() ) { 
		cout << "Couldn't load file: " << newName << endl;
		exit(1);

	}
	
	string line;
	int id,x,y,w,h;
	while ( true ) {
		getline( fout, line, ' ' );
		if ( !fout.good() ) {
			break;
		}
		id = atoi( line.c_str() );
		getline( fout, line, ' ' );
		x = atoi( line.c_str() );
		getline( fout, line, ' ' );
		y = atoi( line.c_str() );
		getline( fout, line, ' ' );
		w = atoi( line.c_str() );
		getline( fout, line, ' ' );
		h = atoi( line.c_str() );
		
		Image* addThis = new Image( x, y, w, h );
		t->images.insert( make_pair( id, addThis ) );
		//~ addThis->toString();
		getline( fout, line, '\n' );
		
	}
	
	fout.close();
	
	textures.insert( make_pair( texID, t ) );
	
	//~ texture = i.texture;
	
	return texID;
	
}

void ImageHandler::blit(int textureID, int imageID, float angle, int overrideW, int overrideH ) {
	map<int, TextureHandler*>::iterator textureIter = textures.find( textureID );
	if ( textureIter == textures.end() ) {
		cout << "That texture ID doesn't exist: " << textureID << endl;
		return;
	}
	TextureHandler* th = textureIter->second;
	
	map<int, Image*>::iterator i = th->images.find( imageID );
	if ( i == th->images.end() ) {
		cout << "ImageHandler does not know ID: " << imageID << endl;
		return;
	}
	
	Image* thisImage = i->second;
	
	glEnable(GL_TEXTURE_2D);
	glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
	
	if ( 1 || boundTexture != textureID ) {
		//~ cout << "The correct texture wasn't bound. Binding texture now." << endl;
		// Bind the texture
		glBindTexture(GL_TEXTURE_2D, textureID );
		
		// Store all of this texture's information in case we use it right after this
		boundTexture = textureID;
		h = th->h;
		w = th->w;
	}
		  
	if ( angle != 9999.0f ) {
		glTranslated(thisImage->w/2, thisImage->h/2, 0.0f); // go to center for rotation
		glRotatef(angle, 0, 0, 1.0);
		glTranslated(-thisImage->w/2, -thisImage->h/2, 0.0f); // go back to corner
	}
	
	float startX = (float)thisImage->x / w;
	float startY = (float)thisImage->y / h;
	float endX = startX + (float)thisImage->w / w;
	float endY = startY + (float)thisImage->h / h;
	//~ cout << "SX: " << startX << " SY: " << startY << endl << " EX: " << endX << " EY: " << endY << endl;
	//~ thisImage->toString();
	int widthDrawn;
	int heightDrawn;
	if ( overrideW != -1 ) {
		widthDrawn = overrideW;
	} else {
		widthDrawn = thisImage->w;
	}
	if ( overrideH != -1 ) {
		heightDrawn = overrideH;
	} else {
		
		heightDrawn = thisImage->h;
	}
	glBegin(GL_QUADS); //~ GL Quads
		glTexCoord2f(startX,startY);
		glVertex2f(0, 0);
	   
		glTexCoord2f(endX,startY);
		glVertex2f(widthDrawn, 0);
	   
		glTexCoord2f(endX,endY);
		glVertex2f(widthDrawn, heightDrawn);

		glTexCoord2f(startX,endY);
		glVertex2f(0, heightDrawn);
	glEnd(); //~ End Quads
}


void ImageHandler::guiBorder( int sideID, int cornerID, int x, int y, int w, int h ) {
	int textureID = workingTextureID;
	map<int, TextureHandler*>::iterator textureIter = textures.find( textureID );
	if ( textureIter == textures.end() ) {
		cout << "That texture ID doesn't exist: " << textureID << endl;
		return;
	}
	TextureHandler* th = textureIter->second;
	
	map<int, Image*>::iterator iter = th->images.find( sideID );
	if ( iter == th->images.end() ) {
		cout << "ImageHandler does not know sideID: " << sideID << endl;
		return;
	}
	Image* sideImage = iter->second;
	
	iter = th->images.find( cornerID );
	if ( iter == th->images.end() ) {
		cout << "ImageHandler does not know cornerID: " << cornerID << endl;
		return;
	}		
	Image* cornerImage = iter->second;
	glPushMatrix();
	glLoadIdentity();
	glTranslatef( x, y, 0 );
	
	// intWidth and intHeight represent how many times to draw a side
	int intWidth = ( w - 2 * cornerImage->w ) / sideImage->h;
	int intHeight = ( h - 2 * cornerImage->h ) / sideImage->h;
	
	// This is how big the last portion has to be to get it pixel-perfect
	// (account for the corners on either end of the side when considering this)
	int remainingWidth = w - ( intWidth * sideImage->h + 2 * cornerImage->w);
	int remainingHeight = h - ( intHeight * sideImage->h + 2 * cornerImage->w );
	
	blit( textureID, cornerID );
	glTranslatef( 0, cornerImage->h, 0 );
	for ( int j = 0; j < intHeight; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	// Draw the remaining
	blit( textureID, sideID, 9999.0f, -1, remainingHeight );
	glTranslatef( 0, remainingHeight, 0 );
	
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intWidth; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingWidth );
	glTranslatef( 0, remainingWidth, 0 );
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intHeight; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingHeight );
	glTranslatef( 0, remainingHeight, 0 );
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intWidth; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingWidth );
	glTranslatef( 0, remainingWidth, 0 );
	
	glPopMatrix();
		
}
void ImageHandler::guiBorder( int sideID, int cornerID, int w, int h ) {
	int textureID = workingTextureID;
	map<int, TextureHandler*>::iterator textureIter = textures.find( textureID );
	if ( textureIter == textures.end() ) {
		cout << "That texture ID doesn't exist: " << textureID << endl;
		return;
	}
	TextureHandler* th = textureIter->second;
	
	map<int, Image*>::iterator iter = th->images.find( sideID );
	if ( iter == th->images.end() ) {
		cout << "ImageHandler does not know sideID: " << sideID << endl;
		return;
	}
	Image* sideImage = iter->second;
	
	iter = th->images.find( cornerID );
	if ( iter == th->images.end() ) {
		cout << "ImageHandler does not know cornerID: " << cornerID << endl;
		return;
	}		
	Image* cornerImage = iter->second;
	glPushMatrix();
	
	// intWidth and intHeight represent how many times to draw a side
	int intWidth = ( w - 2 * cornerImage->w ) / sideImage->h;
	int intHeight = ( h - 2 * cornerImage->h ) / sideImage->h;
	
	// This is how big the last portion has to be to get it pixel-perfect
	// (account for the corners on either end of the side when considering this)
	int remainingWidth = w - ( intWidth * sideImage->h + 2 * cornerImage->w);
	int remainingHeight = h - ( intHeight * sideImage->h + 2 * cornerImage->w );
	
	blit( textureID, cornerID );
	glTranslatef( 0, cornerImage->h, 0 );
	for ( int j = 0; j < intHeight; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	// Draw the remaining
	blit( textureID, sideID, 9999.0f, -1, remainingHeight );
	glTranslatef( 0, remainingHeight, 0 );
	
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intWidth; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingWidth );
	glTranslatef( 0, remainingWidth, 0 );
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intHeight; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingHeight );
	glTranslatef( 0, remainingHeight, 0 );
	
	blit( textureID, cornerID, -90 );
	glTranslatef( cornerImage->w - cornerImage->h, cornerImage->h, 0 );
	for ( int j = 0; j < intWidth; j ++ ) {
		blit( textureID, sideID );
		glTranslatef( 0, sideImage->h, 0 );
	}
	blit( textureID, sideID, 9999.0f, -1, remainingWidth );
	glTranslatef( 0, remainingWidth, 0 );
	
	glPopMatrix();
		
}

void ImageHandler::getImageSize( int &w, int &h, int imageID ) {
	int textureID = workingTextureID;
	map<int, TextureHandler*>::iterator textureIter = textures.find( textureID );
	if ( textureIter == textures.end() ) {
		cout << "That texture ID doesn't exist: " << textureID << endl;
		return;
	}
	TextureHandler* th = textureIter->second;
	
	map<int, Image*>::iterator i = th->images.find( imageID );
	if ( i == th->images.end() ) {
		cout << "ImageHandler does not know ID: " << imageID << endl;
		return;
	}
	
	Image* thisImage = i->second;
	w = thisImage->w;
	h = thisImage->h;
}


void ImageHandler::setWorkingTexture( int id ) {
	workingTextureID = id;
}

int ImageHandler::getWorkingTexture() {
	return workingTextureID;
}
